import {
  BadRequestException,
  Injectable,
  NotFoundException
} from '@nestjs/common';
import { Model } from 'mongoose';
import { InjectModel } from '@nestjs/mongoose';
import { PaymentService } from '@/views/payment/payment.service';
import {
  UserDto,
  UpdateUserDto,
  UserSearchDto,
  UserPageSearchDto
} from '@/dto/user.dto';
import { User, UserDocument } from '@/schema/user.schema';
import { isObject } from 'class-validator';
import dayjs from 'dayjs';

@Injectable()
export class UserService {
  constructor(
    private readonly paymentService: PaymentService,
    @InjectModel(User.name) private userModel: Model<UserDocument>
  ) {}

  findOne(conditions: UserSearchDto) {
    return this.userModel.findOne(conditions, '-__v').exec(); //exec()返回promise对象
  }

  async findById(id: string) {
    const userExists = await this.userModel.findById(id, '-__v').exec();
    if (!userExists) {
      throw new NotFoundException('用户不存在');
    }
    return userExists;
  }

  async create(user: UserDto) {
    const accountExists = await this.userModel
      .findOne({
        account: user.account
      })
      .lean();
    if (accountExists) {
      throw new BadRequestException('账号已存在');
    }
    const mobileExists = await this.userModel
      .findOne({
        mobile: user.mobile
      })
      .lean();
    if (mobileExists) {
      throw new BadRequestException('手机号已绑定用户');
    }
    const userDocument = new this.userModel(user);
    return userDocument.save();
  }

  async update(id: string, user: UpdateUserDto) {
    //.lean() //将查询结果从 Mongoose 文档对象转换为普通的 JavaScript 对象。这通常可以提高性能，因为 Mongoose 文档对象包含额外的 Mongoose 特定的方法和属性，这些在普通对象中是不存在的
    const userExists = await this.userModel.findById(id).lean();
    if (!userExists) {
      throw new NotFoundException('用户不存在');
    }
    return this.userModel
      .findByIdAndUpdate(
        id,
        { ...user, updatedAt: dayjs().format('YYYY-MM-DD HH:mm:ss') },
        { new: true, lean: true }
      )
      .exec();
  }

  async query(
    userPageSearchDto?: UserPageSearchDto
  ): Promise<Api.Common.Page<UserDocument>> {
    const { current = 1, size = 10, ...rest } = userPageSearchDto || {};
    const records = await this.userModel
      .find(rest)
      .skip((current - 1) * size)
      .limit(size)
      .exec();
    const total = await this.userModel.countDocuments(rest);
    return { records, total, current, size };
  }

  findOneByAccountOrMobile(
    param: string | { account?: string; mobile?: string }
  ) {
    if (isObject(param)) {
      return this.userModel.findOne(param).exec();
    }
    return this.userModel
      .findOne({ $or: [{ account: param }, { mobile: param }] })
      .exec();
  }

  pay(name: string) {
    return this.paymentService.pay(name);
  }
}
